/**
	License:		Artistic license 2.0 (see license.txt, also available online at http://www.perlfoundation.org/artistic_license_2_0)
	Authors:		OrbitalLab (http://www.orbitallab.ru/moonglide/), 2007-2009

	File:			COpenGLMatSys.d
	Description:	material system
	Date:			17.01.2008 by Jurec
*/
module moonglide.renderer.opengl.OpenGLMatSys;

import
	moonglide.util.MoonUtil,

	moonglide.renderer.IRendererMatSys,

	moonglide.renderer.opengl.GL,
	moonglide.renderer.opengl.OpenGLRenderer,
	moonglide.renderer.opengl.OpenGLBind,

    moonglide.resources.resobjects.lowlevel.ResMesh,

	moonglide.renderer.IRendererRes;

// input:
//	- Geometry
//	- Lights
//	- Material
//	- but other scene info must be in access, so pointer to render system
//
// output:
//	- Right render of geometry, include multipass, optimization of shaders, etc.

uint RendTypeGL(EMeshRenderType engType)
{
	switch(engType)
	{
		case EMeshRenderType.mrt_default, EMeshRenderType.mrt_fill:
			return GL_TRIANGLES;
		case EMeshRenderType.mrt_fill_strip:
			return GL_TRIANGLE_STRIP;
		case EMeshRenderType.mrt_fill_quads:
			return GL_QUADS;
		case EMeshRenderType.mrt_fill_fan:
			return GL_TRIANGLE_FAN;
		case EMeshRenderType.mrt_line:
			return GL_LINES;
		case EMeshRenderType.mrt_line_strip:
			return GL_LINE_STRIP;
		case EMeshRenderType.mrt_line_loop:
			return GL_LINE_LOOP;
		case EMeshRenderType.mrt_point:
			return GL_POINTS;
		default:
			moonAssert( 0, "default switch called in COpenGLMatSys.RendTypeGL", __FILE__, __LINE__ );
			return 0;
	}
}


//================================================================
/// Material system
//================================================================
class COpenGLMatSys : IMaterialSys
{
	protected:
		COpenGLRenderer			_renderer;
        bool _onlyHdrPass = false,
             _depthPass = false,
             _termalPass = false;
    public:
        bool onlyHdrPass()
        {
            return _onlyHdrPass;
        }
        void onlyHdrPass( bool b )
        {
            _onlyHdrPass = b;
        }

        bool termalPass()
        {
            return _termalPass;
        }
        void termalPass( bool b )
        {
            _termalPass = b;
        }

        bool depthPass()
        {
            return _depthPass;
        }
        void depthPass( bool b )
        {
            _depthPass = b;
        }

        bool passGeom( CEngGeometry rGeom )
        {
            return (rGeom.visible);
        }


        private void rendLightedGeom( CEngGeometry rGeom )
        {
			uint rType = RendTypeGL(rGeom.activeMesh.rendType);
			int length = rGeom.activeMesh.fields["Index"].GetLength();
            void* data = null;

            if(!(( cast(COpenGLRenderer)_renderer).caps.useVBO && rGeom.activeMesh.loaded ))
            	data = rGeom.activeMesh.fields["Index"].GetData();

            void multipassRender()
            {
                int ct = 0;
                foreach( inout li ; rGeom.lights )
                {
                    if( ct == 1 )
                    {
                        glPushAttrib(GL_BLEND);
                        glPushAttrib(GL_DEPTH_TEST);
                        glEnable(GL_BLEND);
                        glBlendFunc(GL_ONE, GL_ONE);
                        glDepthFunc(GL_EQUAL);
                    }
				    resBinder.unBindLights;
                    resBinder.bindLight( li );
                    glDrawElements( rType, length, GL_UNSIGNED_INT, data );
                    ++ct;
                }
                if( ct > 1 )
                {
                    glPopAttrib();
                    glPopAttrib();
                }
            }


            if( rGeom.material.bools["Lighting"] )
            {
                /// NOTE: here we must do optimization. Choice optimal shader for this lighting configuration
                /// if we have not this config - divide it to several passes.
                //if( rGeom.material.canUseSpecialShader(rGeom.lights) )
                //{
                //} else
                    multipassRender();
            } else
                glDrawElements( rType, length, GL_UNSIGNED_INT, data );




        }

		void renderGeom( CEngGeometry rGeom )
		{

			if ( !passGeom(rGeom) )
				return;
			if( !rGeom.activeMesh )
				return;

            if (rGeom.material.bools["term"])
                if (!_termalPass)
                    return;
            if (!rGeom.material.bools["term"])
                if (_termalPass)
                    return;

            glColor4f(1.f,1.f,1.f,1.f);
            bool zPass = (rGeom.material.bools["OnlyHDR"] ^ _onlyHdrPass) || _depthPass;

            resBinder.unBindLights();

            bool useMat = false;
            if(zPass)
            {
  //              glDrawBuffer(GL_NONE);
  //              glReadBuffer(GL_NONE);
                glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
            } else
            {
                resBinder.bindMaterial( rGeom.material );

           //     foreach( inout li ; rGeom.lights )
             //   {
               //     resBinder.bindLight( li );
                //}
            }
GetGLError(__FILE__,__LINE__);

            resBinder.simpleMeshBind = zPass;
			resBinder.bindMesh( rGeom.activeMesh );


            rendLightedGeom( rGeom );


			resBinder.unBindMesh( rGeom.activeMesh );

			if(zPass)
			{
      //          glDrawBuffer(GL_BACK);
      //          glReadBuffer(GL_BACK);
                glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
			} else
			{
                resBinder.unBindMaterial( rGeom.material );
			}
		}

		this( COpenGLRenderer re )
		{
			_renderer 	= 	re;
			resBinder	= 	new COpenGLRendererBind( re.caps, re.shaderMan, re.resLoader );
		}

		~this()
		{
			delete resBinder;
		}
}
